﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Linq;
using System.Collections;
using System.Xml.Linq;

namespace Sofire.Data.XSql
{
    internal class XSqlForeachNode : XSqlTrimNodeBase, IXSqlForeachNode
    {
        public const string NodeName = "foreach";

        private string _Var;
        public string Var
        {
            get
            {
                return this._Var;
            }
            set
            {
                this._Var = value;
            }
        }

        private string _In;
        public string In
        {
            get
            {
                return this._In;
            }
            set
            {
                this._In = value;
            }
        }

        private string _Index;
        public string Index
        {
            get
            {
                return this._Index;
            }
            set
            {
                this._Index = value;
            }
        }

        public override XSqlType Type
        {
            get { return XSqlType.Foreach; }
        }

        public override XObject CreateXObject()
        {
            XElement element = new XElement(NodeName);
            element.SetAttributeValue(XSqlAttributes.Var, this._Var);
            element.SetAttributeValue(XSqlAttributes.In, this._In);
            element.SetAttributeValue(XSqlAttributes.Index, this._Index);
            element.SetAttributeValue(XSqlAttributes.Trim, this.Trim);
            this.CreateXChildren(element);
            return element;
        }

        protected override void Load(XmlNode node)
        {
            base.Load(node);
            this._Var = this.GetAttribute(node, XSqlAttributes.Var);
            this._In = this.GetAttribute(node, XSqlAttributes.In);
            this._Index = this.TryGetAttribute(node, XSqlAttributes.Index);

        }

        public override string Compile(XSqlParameterCollection parameters)
        {
            var inParameter = parameters[this._In];

            IEnumerable value = null;
            if(inParameter != null)
            {
                var pValue = inParameter.Value;

                value = pValue as IEnumerable;
                if(value == null && pValue is string)
                {
                    var s = Convert.ToString(pValue);
                    value = s.Split(',');
                }
                if(value != null) goto SUCCESS;
            }
            this.ThrowException(XSqlError.Invalid, XSqlAttributes.In);

        SUCCESS:
            if(parameters.Contains(this._Var)) this.ThrowException(XSqlError.NoExists, XSqlAttributes.Var);
            if(this._Index != null && parameters.Contains(this._Index)) this.ThrowException(XSqlError.NoExists, XSqlAttributes.Index);

            StringBuilder builder = new StringBuilder();

            #region Compile Text

            var index = 0;
            string newName = null;
            if(this._Index == null)
            {
                Func<string, string> func = (oldName) =>
                {
                    if(oldName == this._Var) return newName;
                    return oldName;
                };
                parameters.NameConverter += func;
                foreach(var item in value)
                {
                    newName = this._Var + "_" + (index++);

                    //parameters.Add(newName, item);

                    builder.Append(this.Children.Compile(parameters));
                }
                parameters.NameConverter -= func;
            }
            else
            {
                string newIndexName = null;


                Func<string, string> func = (oldName) =>
                {
                    if(oldName == this._Var) return newName;
                    if(oldName == this._Index) return newIndexName;
                    return oldName;
                };
                parameters.NameConverter += func;
                foreach(var item in value)
                {
                    newName = this._Var + "_" + (index);
                    newIndexName = this._Index + "_" + (index);

                    //parameters.Add(newName, item);
                    parameters.Add(newIndexName, index++);

                    builder.Append(this.Children.Compile(parameters));

                }
                parameters.NameConverter -= func;

            }

            parameters.Remove(this._In);
            #endregion

            return this.TrimText(builder.ToString());
        }
    }
}
